﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

using Seven.Site.Mvc.Attributes;

namespace Seven.Site.Mvc.Filters
{
    /// <summary>
    /// 权限验证
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class AuthAttribute : AuthorizeAttribute
    {
        #region 属性

        /// <summary>
        /// 当前控制器名称
        /// </summary>
        private string ControllerName { get; set; }

        /// <summary>
        /// 当前动作名称
        /// </summary>
        private string ActionName { get; set; }

        /// <summary>
        /// 是否允许匿名访问
        /// </summary>
        private bool AllowAnonymous { get; set; }

        /// <summary>
        /// 是否登录即可访问
        /// </summary>
        private bool AllowLogined { get; set; }

        /// <summary>
        /// 是否页面
        /// </summary>
        private bool IsViewPage { get; set; }

        #region 最终结果

        /// <summary>
        /// 无权使用
        /// </summary>
        private bool Limited { get; set; }

        /// <summary>
        /// 未登录
        /// </summary>
        private bool UnLogin { get; set; }

        /// <summary>
        /// 登录超时
        /// </summary>
        private bool LoginTimeout { get; set; }

        #endregion

        #endregion

        /// <summary>
        /// 授权判定核心
        /// </summary>
        /// <param name="httpContext">筛选器上下文</param>
        /// <returns></returns>
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (this.AllowAnonymous)
            { return base.AuthorizeCore(httpContext); }
            else
            {
                bool Pass = httpContext.User.Identity.IsAuthenticated;
                string UserName = httpContext.User.Identity.Name;
                if (Pass)
                {
                    if (!AllowLogined)
                    {
                        var MenuFunctionRange = new Seven.Service.Security.Account().GetCurrentUserMenuFunctionRange(UserName);
                        if (!MenuFunctionRange.Any(a => a.Menu.ControllerName.Equals(this.ControllerName, StringComparison.InvariantCultureIgnoreCase) && a.ActionName.Equals(this.ActionName, StringComparison.InvariantCultureIgnoreCase)))
                        {
                            this.Limited = true;
                        }
                    }
                }
                else
                {
                    if (string.IsNullOrWhiteSpace(UserName))
                    {
                        this.UnLogin = true;
                    }
                    else
                    {
                        this.LoginTimeout = true;
                    }
                }
            }
            return (this.Limited || this.UnLogin || this.LoginTimeout) ? false : base.AuthorizeCore(httpContext);
        }

        /// <summary>
        /// 在过程请求授权时调用
        /// 自带的AllowAnonymous特性依旧会执行本方法，但会略过AuthorizeCore方法的执行。
        /// </summary>
        /// <param name="filterContext">筛选器上下文</param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var AD = filterContext.ActionDescriptor;
            this.ControllerName = AD.ControllerDescriptor.ControllerName;
            this.ActionName = AD.ActionName;

            this.AllowAnonymous = false;
            this.AllowLogined = false;
            this.IsViewPage = false;
            this.Limited = false;
            this.LoginTimeout = false;
            this.UnLogin = false;
            this.AllowAnonymous = AD.GetCustomAttributes(typeof(AnonymousAttribute), true).Length > 0 || AD.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Length > 0;
            if (!this.AllowAnonymous)
            {
                this.AllowLogined = AD.GetCustomAttributes(typeof(LoginAttribute), true).Length > 0;
                this.IsViewPage = AD.GetCustomAttributes(typeof(ViewPageAttribute), true).Length > 0;
                base.OnAuthorization(filterContext);
            }
        }

        /// <summary>
        /// 处理未能授权的 HTTP 请求
        /// </summary>
        /// <param name="filterContext">筛选器上下文</param>
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            #region 无权访问
            if (this.Limited)
            {
                string message = HttpUtility.HtmlEncode(CustomStatusCode.无权访问.ToString() + "指定路径：/" + this.ControllerName + "/" + this.ActionName);
                if (this.IsViewPage)
                {
                    filterContext.Result = new RedirectResult("/Blank/Index?msg=" + message);
                }
                else
                {
                    filterContext.Result = new HttpStatusCodeResult((int)CustomStatusCode.无权访问, message);
                }
            }
            #endregion

            #region 未登录
            if (this.UnLogin)
            {
                if (this.IsViewPage)
                {
                    //会跳转到 web.config 中<authentication mode="Forms"><forms loginUrl="~/" timeout="2880" /></authentication>定义的  loginUrl="~/"，并且会将当前url以参数方式传入loginUrl
                    base.HandleUnauthorizedRequest(filterContext);
                }
                else
                {
                    string message = HttpUtility.HtmlEncode(CustomStatusCode.未登录.ToString());
                    filterContext.Result = new HttpStatusCodeResult((int)CustomStatusCode.未登录, message);
                }
            }
            #endregion

            #region 登录超时
            if (this.LoginTimeout)
            {
                if (this.IsViewPage)
                {
                    filterContext.Result = new RedirectResult("/Blank/Index?msg=" + CustomStatusCode.登录超时.ToString());
                }
                else
                {
                    string message = HttpUtility.HtmlEncode(CustomStatusCode.登录超时.ToString());
                    filterContext.Result = new HttpStatusCodeResult((int)CustomStatusCode.登录超时, CustomStatusCode.登录超时.ToString());
                }
            }
            #endregion
        }
    }
}
